#include <iostream>
#include <thread>

using namespace std;

//========================================================
// ​​1.ps -e：-e用于显示所有进程​​
// ​​2.ps -ef：-f选项定义为full-format listing​​
// ​​3.ps -eF：-F选项添加了进程使用内存方面的一些信息​​
// ​​4.ps -eLf：-L用于显示线程​​
// ​​5.ps -ejH：显示进程树​​
// ​​5.ps工具标识进程的5种状态码:​​
// ​​6.ps -ef，ps aux，ps -eo​​
//========================================================


// $ g++ thread_release.cpp -g -O0

class A
{
public:
    ~A() { std::cout << "A::~A()" << std::endl; }
};

void twork()
{
    std::this_thread::sleep_for(std::chrono::seconds(10));
    cout << "--- end ---" << endl;
}

int test_thread_lifecycle()
{
    A a;
    a.~A();

    std::thread t(twork);
    t.detach();
    // t.join();
    cout << sizeof(t) << endl;
    t.~thread(); // 线程析构函数中调用了std::terminate(), 所以创建线程后必须 t.detach() 或者 t.join(), 否则抛异常,
                 // #7  0x00007ffff7cae2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6
                 // #8  0x00005555555555f1 in std::thread::~thread (this=0x7fffffffddb8, __in_chrg=<optimized out>)  at /usr/include/c++/11/bits/std_thread.h:152
    cout << sizeof(t) << endl;

    std::this_thread::sleep_for(std::chrono::seconds(30));
    return 0;
}

/*************************************************
 *
 * $ ps -eLf | grep a.out | grep -v grep
 * 测试 test_thread_lifecycle() 得到, 无论 t.detach() 还是 t.join() 情况下, 即使调用了 t.~thread() 析构函数, 释放掉了对象,
 * 只要主线程不退出, 依然会继续执行 twork() 线程回调函数,
 * 通过 "ps -eLf | grep a.out | grep -v grep" 可以看到 t.detach() t.~thread() 执行了析构之后, 还是存在2个线程,
 * 另外 t.join() 是因为阻塞了, 执行不到 t.~thread() , 所以也存在2个线程,
 * 所以 std::thread 只是负责启动线程, 只要起来之后, 就跟这个对象无关了, thread 的生命周期由底层 pthread 决定,
 *
 *************************************************/

// #####################################################################


void twork_nanosleep()
{
    std::this_thread::sleep_for(std::chrono::nanoseconds(20));
    cout << "--- end ---" << endl;
}

class thread_size
{
#define MAX_COUNT (1024 * 1024)
    // sizeof(std::thread) 是 8个字节, 那么生成 COUNT 就应该是 8M 大小,
public:
    thread_size()
    {
        for (size_t i = 0; i < MAX_COUNT; i++)
        {
            // 上面例子也验证了开启线程后, 线程生命周期由底层 pthread 决定, 这样会导致进程中生产了大量的线程,
            // 这里使用 twork_nanosleep(20) 函数来验证, 当线程执行完毕退出以后, 进程的内存大小, 

            std::thread t(twork_nanosleep);
            t.join();  // 这里使用 join() 是为了让子线程执行完毕退出后, 不执行 t.~thread() 的时候, 使用 $ cat /proc/pid/status   VmRSS 内存,  VmRSS对应的值就是物理内存占用，
            std::this_thread::sleep_for(std::chrono::milliseconds(10));   
        }
    }
    ~thread_size() {}
};

int test_thread_destructor()
{
    thread_size t_size;
    cout << "thread_size::thread_size() construct success!" << endl;
    cout << "please input any char" << endl;
    getchar();
    return 0;
}

/*************************************************
 *
 * $ ps -eLf | grep a.out | grep -v grep
 * $ ps -eLf | grep a.out | grep -v grep
 * $ top -p pid 查看信息,
 * $ ps -aux | grep a.out | grep -v grep
 *      zhangxi    21489  1.8  0.0  79780  2104 pts/0    S+   10:45   0:06 ./a.out   #==> 内存一直在 79780
 *      使用 $ cat /proc/pid/status   VmRSS 内存, VmRSS对应的值就是物理内存占用，VmRSS:2304 kB, 另外还可以通过 top 命令动态查看内存占用
 *      发现  thread_size(){} 构造时候, 尽管一直生产 std::thread 对象, 并没有释放, 但是内存却一直稳定, 没有内存泄漏,
 * 
 * 测试 test_thread_destructor() 得到, 使用 std::thread() 生产线程, t.join(), 即使不调用 ~thread(), 
 * 当pthread执行完毕销毁掉, ~thread() 占用的空间也回收了, 并没有内存泄漏。
 *
 *************************************************/



/**
 * 
 * $ cat /proc/110949/status 
Name:   a.out
Umask:  0002
State:  S (sleeping)
Tgid:   110949
Ngid:   0
Pid:    110949
PPid:   96665
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 4 24 27 30 46 122 134 135 999 1000 
NStgid: 110949
NSpid:  110949
NSpgid: 110949
NSsid:  96665
VmPeak:   145316 kB
VmSize:    79780 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      2100 kB
VmRSS:      2100 kB
RssAnon:             180 kB
RssFile:            1920 kB
RssShmem:              0 kB
VmData:     8584 kB
VmStk:       132 kB
VmExe:         8 kB
VmLib:      3472 kB
VmPTE:        56 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:        1
SigQ:   0/15244
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000100000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Seccomp_filters:        0
Speculation_Store_Bypass:       thread vulnerable
SpeculationIndirectBranch:      conditional enabled
Cpus_allowed:   00000000,00000000,00000000,00000003
Cpus_allowed_list:      0-1
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        4990
nonvoluntary_ctxt_switches:     21
 */


int main(int argc, char const *argv[])
{
    // test_thread_lifecycle();
    test_thread_destructor();
    return 0;
}
